#include "Lexical.h"

void lexical::bootLexical() {
	dict = {
		{"Ident", "IDENFR"},
		{"IntConst", "INTCON"},
		{"FormatString", "STRCON"},
		{"main", "MAINTK"},
		{"const", "CONSTTK"},
		{"int", "INTTK"},
		{"break", "BREAKTK"},
		{"continue", "CONTINUETK"},
		{"if", "IFTK"},
		{"else", "ELSETK"},
		{"!", "NOT"},
		{"&&", "AND"},
		{"||", "OR"},
		{"while", "WHILETK"},
		{"getint", "GETINTTK"},
		{"printf", "PRINTFTK"},
		{"return", "RETURNTK"},
		{"+", "PLUS"},
		{"-", "MINU"},
		{"void", "VOIDTK"},
		{"*", "MULT"},
		{"/", "DIV"},
		{"%", "MOD"},
		{"<", "LSS"},
		{"<=", "LEQ"},
		{">", "GRE"},
		{">=", "GEQ"},
		{"==", "EQL"},
		{"!=", "NEQ"},
		{"=", "ASSIGN"},
		{";", "SEMICN"},
		{",", "COMMA"},
		{"(", "LPARENT"},
		{")", "RPARENT"},
		{"[", "LBRACK"},
		{"]", "RBRACK"},
		{"{", "LBRACE"},
		{"}", "RBRACE"}
	};
}

bool lexical::isIdent(std::string str) {
	if (str.empty()) return false;
	for (auto s : str) {
		if (!isdigit(s) && !isupper(s) && !islower(s) && s != '_') return false;
	}
	return isalpha(str[0]) || str[0] == '_';
}

bool lexical::isIdentCharacter(char c) {
	return isalnum(c) || c == '_';
}

bool lexical::isIntConst(std::string str) {
	if (str.empty()) return false;
	if (str[0] == '0' && str.length() > 1) return false;
	for (auto s : str) {
		if (!isdigit(s)) return false;
	}
	return true;
}

bool lexical::isFormatString(std::string str) {
	return str.length() >= 2 && str.front() == '"' && str.back() == '"';
}

std::vector<std::pair<std::string, std::string>> lexical::resolve(std::vector<std::string> context) {
	bool isNote = false;
	std::vector<std::pair<std::string, std::string>> result;
	for (auto str : context) {
		int p = 0;
		std::string cur;
		while (p < str.length()) {
			while (!isNote && p < str.length() && isIdentCharacter(str[p])) {
				cur += str[p];
				p++;
			}
			if (dict.count(cur)) {
				result.push_back({ dict[cur], cur });
				cur.clear();
			}
			else if (isIdent(cur)) {
				result.push_back({ "IDENFR", cur });
				cur.clear();
			}
			else if (isIntConst(cur)) {
				result.push_back({ "INTCON", cur });
				cur.clear();
			}
			else if (isFormatString(cur)) {
				result.push_back({ "STRCON", cur });
				cur.clear();
			}

			if (p + 1 < str.length() && str[p] == '/' && str[p + 1] == '/') {
				while (p < str.length()) {
					if (p + 1 < str.length() && str[p] == '*' && str[p + 1] == '/') {
						isNote = false;
						p += 2;
					}
					p++;
				}
			}

			if (p + 1 < str.length() && str[p] == '/' && str[p + 1] == '*') {
				isNote = true;
			}
			if (p + 1 < str.length() && str[p] == '*' && str[p + 1] == '/') {
				isNote = false;
				p += 2;
			}

			if (p < str.length() && !isNote && (!cur.empty() || !isspace(str[p]))) {
				cur += str[p];
			}
			if (dict.count(cur)) {
				if (cur == "<" || cur == "=" || cur == ">" || cur == "!") {
					if (p + 1 < str.length() && str[p + 1] == '=') {
						p++;
						cur += str[p];
					}
				}
				result.push_back({ dict[cur], cur });
				cur.clear();
			}
			else if (isIntConst(cur)) {
				result.push_back({ "INTCON", cur });
				cur.clear();
			}
			else if (isFormatString(cur)) {
				result.push_back({ "STRCON", cur });
				cur.clear();
			}
			p++;
		}
	}
	return result;
}